package com.idp.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.idp.common.enums.DataStatusEnum;
import com.idp.common.enums.MessageEnum;
import com.idp.common.constants.SystemParam;
import com.idp.common.enums.UserStatusEnum;
import com.idp.common.error.SystemException;
import com.idp.common.model.PageModel;
import com.idp.common.utils.ContextUtil;
import com.idp.common.utils.EncodeUtil;
import com.idp.system.dto.SysUserDto;
import com.idp.system.dto.SysUserSearchDto;
import com.idp.system.entity.SysRoleEntity;
import com.idp.system.entity.SysUserEntity;
import com.idp.system.entity.SysUserRoleEntity;
import com.idp.system.excel.SysUserExcelDto;
import com.idp.system.excel.SysUserImportListener;
import com.idp.system.mapper.SysRoleMapper;
import com.idp.system.mapper.SysUserMapper;
import com.idp.system.mapper.SysUserRoleMapper;
import com.idp.system.service.SysUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户Service实现类
 * @author King
 */
@Service
public class SysUserServiceImpl implements SysUserService {

	private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);

	@Autowired
	private SysUserMapper sysUserMapper;
	@Autowired
	private SysUserRoleMapper sysUserRoleMapper;
	@Autowired
	private SystemParam systemParam;
	@Autowired
	private SysRoleMapper sysRoleMapper;

	@Override
	public PageModel<SysUserDto> findByPage(SysUserSearchDto sysUserSearchDto) {

		PageModel<SysUserDto> page = new PageModel<SysUserDto>();
		page.setList(sysUserMapper.getList(sysUserSearchDto));

		return page;
	}

	@Override
	public SysUserDto getById(String id) {

		if(StrUtil.isEmpty(id)) {
			throw new SystemException(MessageEnum.PARAM_ERROR);
		}

		SysUserEntity sysUser = sysUserMapper.selectById(id);

		if(sysUser == null) {
			throw new SystemException(MessageEnum.DATA_NOT_EXIST);
		}

		SysUserDto userDto = BeanUtil.toBean(sysUser, SysUserDto.class);
		List<String> roleIds = sysUserRoleMapper.findRoleIdsByUserId(id);
		userDto.setRoleIds(roleIds);

		return userDto;
	}

	@Override
	@Transactional(rollbackFor=Exception.class)
	public void add(SysUserDto sysUserDto) {

		LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(SysUserEntity::getDelFlag, UserStatusEnum.NORMAL.code);
		queryWrapper.eq(SysUserEntity::getUname, sysUserDto.getUname());

		SysUserEntity checkUser = sysUserMapper.selectOne(queryWrapper);

		if(checkUser != null) {
			throw new SystemException("用户名已存在");
		}

		SysUserEntity sysUser = BeanUtil.toBean(sysUserDto, SysUserEntity.class);
		String userId = IdUtil.simpleUUID();
		sysUser.setId(userId);
		String newPwd = EncodeUtil.encryptPassword(systemParam.getUserDefaultPwd());
		sysUser.setPwd(newPwd);
		sysUser.setDelFlag(DataStatusEnum.NORMAL.code);
		sysUser.setCreateUser(ContextUtil.getLoginUserId());
		sysUser.setCreateTime(new Date());
		sysUserMapper.insert(sysUser);

		List<String> roleIds = sysUserDto.getRoleIds();

		if(roleIds != null && roleIds.size() > 0) {
			for(String roleId : roleIds) {
				SysUserRoleEntity userRole = new SysUserRoleEntity();
				userRole.setUserId(userId);
				userRole.setRoleId(roleId);
				sysUserRoleMapper.insert(userRole);
			}
		}
	}

	@Override
	public void update(SysUserDto sysUserDto) {

		SysUserEntity sysUser = sysUserMapper.selectById(sysUserDto.getId());
		if(sysUser == null) {
			throw new SystemException(MessageEnum.DATA_NOT_EXIST);
		}

		BeanUtil.copyProperties(sysUserDto, sysUser);
		sysUser.setUpdateUser(ContextUtil.getLoginUserId());
		sysUser.setUpdateTime(new Date());
		sysUserMapper.updateById(sysUser);

		LambdaQueryWrapper<SysUserRoleEntity> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(SysUserRoleEntity::getUserId, sysUser.getId());
		sysUserRoleMapper.delete(queryWrapper);

		List<String> roleIds = sysUserDto.getRoleIds();

		if(roleIds != null && roleIds.size() > 0) {

			for(String roleId : roleIds) {

				SysUserRoleEntity userRole = new SysUserRoleEntity();
				userRole.setUserId(sysUser.getId());
				userRole.setRoleId(roleId);

				sysUserRoleMapper.insert(userRole);
			}
		}
	}

	@Override
	public void delete(String id) {

		SysUserEntity sysUser = sysUserMapper.selectById(id);

		if(sysUser == null) {
			throw new SystemException(MessageEnum.DATA_NOT_EXIST);
		}

		sysUser.setDelFlag(DataStatusEnum.DELETED.code);
		sysUser.setUpdateUser(ContextUtil.getLoginUserId());
		sysUser.setUpdateTime(new Date());
		sysUserMapper.updateById(sysUser);

		LambdaQueryWrapper<SysUserRoleEntity> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(SysUserRoleEntity::getUserId, sysUser.getId());
		sysUserRoleMapper.delete(queryWrapper);
	}

	@Override
	public void resetPwd(String id) {

		SysUserEntity sysUser = sysUserMapper.selectById(id);

		if(sysUser == null) {
			throw new SystemException(MessageEnum.DATA_NOT_EXIST);
		}

		String newPwd = EncodeUtil.encryptPassword(systemParam.getUserDefaultPwd());
		sysUser.setPwd(newPwd);
		sysUser.setUpdateUser(ContextUtil.getLoginUserId());
		sysUser.setUpdateTime(new Date());

		sysUserMapper.updateById(sysUser);
	}

	@Override
	public void updatePwd(String userId, String oldPwd, String newPwd) {

		SysUserEntity sysUser = sysUserMapper.selectById(userId);

		if(sysUser == null) {
			throw new SystemException(MessageEnum.DATA_NOT_EXIST);
		}

		String oldPwdEncode = EncodeUtil.encryptPassword(oldPwd);
		String newPwdEncode = EncodeUtil.encryptPassword(newPwd);

		if(oldPwdEncode.equals(sysUser.getPwd())) {

			sysUser.setPwd(newPwdEncode);
			sysUser.setUpdateUser(ContextUtil.getLoginUserId());
			sysUser.setUpdateTime(new Date());
			sysUserMapper.updateById(sysUser);
		} else {

			throw new SystemException("旧密码错误");
		}
	}

	@Override
	public List<SysUserDto> findValidUsers() {

		LambdaQueryWrapper<SysUserEntity> query = new LambdaQueryWrapper<SysUserEntity>();
		query.eq(SysUserEntity::getDelFlag, DataStatusEnum.NORMAL.code);
		List<SysUserEntity> list = sysUserMapper.selectList(query);

		return BeanUtil.copyToList(list, SysUserDto.class);
	}

	@Override
	public void exportExcel(SysUserSearchDto sysUserSearchDto, HttpServletResponse response) {

		List<SysUserDto> list = sysUserMapper.getList(sysUserSearchDto);
		List<SysUserExcelDto> excelList = BeanUtil.copyToList(list, SysUserExcelDto.class);

		OutputStream out = null;

		try {
			out = response.getOutputStream();

			EasyExcel.write(out, SysUserExcelDto.class).sheet("用户信息").doWrite(excelList);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new SystemException("导出失败");
		} finally {
			if(out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

	@Override
	public void importExcel(MultipartFile file) {

		InputStream in = null;

		try {
			in = file.getInputStream();

			List<SysRoleEntity> roleList = sysRoleMapper.selectList(null);
			Map<String, String> roleMap = roleList.stream().collect(Collectors.toMap(SysRoleEntity::getRoleName, SysRoleEntity::getId));

			SysUserImportListener importListener = new SysUserImportListener(sysUserMapper, systemParam, roleMap, sysUserRoleMapper);
			EasyExcel.read(in, SysUserExcelDto.class, importListener).sheet().doRead();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new SystemException("导入失败");
		} finally {
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

}
